package com.szwistar.common.comm;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.szwistar.common.ERR;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * 异步结果
 * @author 张勇
 */
public class AsyncResult<T> extends CountDownLatch implements Future<T> {
	protected static final Logger LOG = LoggerFactory.getLogger(AsyncResult.class);

	public static final int StatusPending = 0;		// 结果未定
	public static final int StatusDone = 1;			// 结果已经就绪
	public static final int StatusCancelled = -1;	// 结果已取消

	public static AsyncResult<?> ok() {
		return new AsyncResult<Object>(0, null, null);
	}

	public static AsyncResult<?> ok(Object ret) {
		return new AsyncResult<Object>(0, null, ret);
	}

	public static AsyncResult<?> error(int code, String message, Object... args) {
		if(message == null) {
			message = "";
		} else if(args != null) {
			message = String.format(message, args);
		}
		return new AsyncResult<Object>(code, message);
	}

	public static AsyncResult<?> error(ERR err, String message, Object... args) {
		if(message == null) { message = err.msg(); }
		return error(err.code(), message, args);
	}

	// 状态码
	protected int status = StatusPending;
	// 等待超时时间(ms)
	protected int waitTimeout = 1000;
	// 开始等待时间
	protected long beginWaitTime = 0;
	// 花费的时间(ms)
	protected int elapsedTime = 0;

	// 这些附带的结果，有任一个有值，就认为结果就绪了
	// 1.附带的错误码
	protected int errCode = 0;
	// 2.附带的消息
	protected String msg = null;
	// 3.附带的数据结构
	protected T result = null;

	//@JsonIgnore
	public int getErrCode() { return errCode; }
	public void setErrCode(Integer errCode) { this.errCode = errCode; }
	//@JsonIgnore
	public void setMsg(String msg) { this.msg = msg; }
	public String getMsg() { return msg; }
	//@JsonIgnore
	public T getResult() { return result; }
	public void setResult(T result) { this.result = result; }
	@Override
	@JsonIgnore
	public long getCount() { return super.getCount(); }

	/**
	 * 构造函数：创建一个异步的结果
	 * @param waitTimeout 默认超时时间
	 */
	public AsyncResult(int waitTimeout) {
		// 1: 表示锁定，直到结果就绪
		super(1);
		this.status = StatusPending;
		this.waitTimeout = waitTimeout;
	}

	/**
	 * 构造函数：创建一个同步的结果（结果已知），不用再等待了
	 * @param errCode 错误码
	 * @param msg 描述信息
	 * @param result 结果对象
	 */
	public AsyncResult(int errCode, String msg, T result) {
		super(0); // 0: 表示结果已经就绪了，直接放行
		doneWithResult(errCode, msg, result);
	}

	/**
	 * 构造函数：创建一个同步的结果（结果已知），不用再等待了
	 * @param errCode 错误码
	 * @param msg 描述信息
	 */
	public AsyncResult(int errCode, String msg) { this(errCode, msg, null); }

	/**
	 * 填写结果并放行等待
	 * @param errCode 错误码
	 * @param msg 描述信息
	 * @param result 结果对象
	 */
	public void doneWithResult(int errCode, String msg, T result) {
		this.errCode = errCode;
		this.msg = msg;
		this.result = result;

		// 计算消耗的时间
		elapsedTime = (int) (System.currentTimeMillis() - beginWaitTime);

		// 结果就绪了，放行
		status = StatusDone;
		countDown();
	}

	/**
	 * 取得默认超时时间(ms)
	 */
	@JsonIgnore
	public int getWaitTimeout() { return waitTimeout; }

	/**
	 * 获取已经等待的时间(ms)
	 */
	public int getElapsedTime() {
		if(status == StatusPending) {
			elapsedTime = (int) (System.currentTimeMillis() - beginWaitTime);
		}
		return elapsedTime;
	}

	/**
	 * 取消结果，并放行，里面的数据是无效的！
	 */
	@Override
	public boolean cancel(boolean mayInterruptIfRunning) {
		status = StatusCancelled;
		countDown();
		return true;
	}

	/**
	 * 结果是否已经取消
	 */
	@JsonIgnore
	@Override
	public boolean isCancelled() {
		return status == StatusCancelled;
	}

	/**
	 * 结果是否已经就绪
	 */
	@JsonIgnore
	@Override
	public boolean isDone() {
		return status == StatusDone;
	}

	/**
	 * 结果是否还未确定(还在等待)
	 */
	@JsonIgnore
	public boolean isPending() {
		return status == StatusPending;
	}

	/**
	 * 等待返回结果(使用默认超时时间)
	 */
	@JsonIgnore
	@Override
	public T get() throws InterruptedException {
		return get(waitTimeout);
	}

	/**
	 * 等待收到命令的响应
	 * @param timeout 等待超时时间(ms)
	 */
	@JsonIgnore
	public T get(long timeout) throws InterruptedException {
		return get(timeout, TimeUnit.MILLISECONDS);
	}

	/**
	 * 等待返回结果
	 * @param timeout 等待超时时间
	 * @param unit 超时时间的单位
	 */
	@JsonIgnore
	@Override
	public T get(long timeout, TimeUnit unit) throws InterruptedException {
		return waitReturn(timeout, unit) ? result : null;
	}

	/**
	 * 等待收到命令的响应(超时时间为默认值，见)
	 * @return true 收到响应；false 超时未收到响应
	 */
	public boolean waitReturn() {
		return waitReturn(waitTimeout);
	}

	/**
	 * 等待收到命令的响应
	 * @param timeout 等待超时时间(ms)
	 * @return true 收到响应；false 超时未收到响应
	 */
	public boolean waitReturn(long timeout) {
		return waitReturn(timeout, TimeUnit.MILLISECONDS);
	}

	/**
	 * 等待收到命令的响应
	 * @param timeout 等待超时时间
	 * @param unit 超时时间的单位
	 * @return true 收到响应；false 超时未收到响应
	 * @throws InterruptedException
	 */
	protected boolean waitReturn(long timeout, TimeUnit unit) {
		if(!isPending()) { return true; }
		if(timeout <= 0) { return false; }
		boolean ret = false;

		// 重置等待开始时间
		beginWaitTime = System.currentTimeMillis();

		try {
			if(super.await(timeout, unit)) {
				ret = true;
			} else {
				errCode = -500; // 设置错误码
				msg = "等待超时";
				cancel(true);   // 取消结果并放行
			}
		} catch (InterruptedException e) {
			errCode = -500;   // 设置错误码
			msg = "中止等待";
			cancel(true);     // 取消结果并放行
		}

		elapsedTime = (int) (System.currentTimeMillis() - beginWaitTime);
		//LOG.debug("本次等待花费时间：{} ms", elapsedTime);
		return ret;
	}

	@Override
	public String toString() {
		return String.format("AsyncResult[errCode=%d, msg='%s', result='%s']", errCode, msg, result);
	}
}
